/*******************************************************************************
 * Copyright (c) 2005, 2014 springside.github.io
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *******************************************************************************/
package com.ly.wxstore.service.account;

import java.io.Serializable;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Objects;
import com.ly.wxstore.comm.RegisterFrom;
import com.ly.wxstore.entity.MarketingAccount;

public class ShiroDbRealm extends AuthorizingRealm {

	private static Logger logger = LoggerFactory.getLogger(ShiroDbRealm.class);

	public static final String test_token = "test_00001";

	@Autowired
	protected AccountService accountService;

	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof WeixinOAuthToken; // 表示此Realm只支持WeixinOAuthToken类型
	}

	/**
	 * 认证回调函数,登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		logger.info("doGetAuthenticationInfo");
		WeixinOAuthToken token = (WeixinOAuthToken) authcToken;

		logger.info("authcToken--->>{code：" + token.getCode() + ",state：" + token.getState() + ",host:" + token.getHost() + ",rememberMe:" + token.isRememberMe() + "}");

		try {
			if (StringUtils.isBlank(token.getCode())) {
				throw new AuthenticationException("没有微信code");// 没有code
			} else if (test_token.equals(token.getCode())) {
				//从浏览器其登录系统进入测试模式
				String opid=token.getState();//openid
				// 根据openid读取用户账号信息
				MarketingAccount account = accountService.getByOpenid(opid);

				return new SimpleAuthenticationInfo(new ShiroUser(account.getOpenid(), account.getSid()), token.getCredentials(), getName());
				
			}else{
				String openId = accountService.receiveWeixinUserInfo(token.getCode());

				// 根据openid读取用户账号信息
				MarketingAccount account = accountService.getByOpenid(openId);

				// 用户在关注微信公众号时会注册账号，如果在此没有账号信息，说明用户还没有关注微信公众号，这说明用户是直接访问链接进入系统。通过网页授权进入系统。
				// 通过OAuth页面授权注册账号
				if (account == null) {
					account = accountService.regiest(openId, RegisterFrom.oauth);
				}

				return new SimpleAuthenticationInfo(new ShiroUser(account.getOpenid(), account.getSid()), token.getCredentials(), getName());
			}
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			
			throw new AuthenticationException("系统太累了，休息一下再来！",e);
		}

		
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addRole("user");
		return info;
	}

	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}

	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {
		private static final long serialVersionUID = -1373760761780840081L;

		public String openid;
		public String sid;

		/**
		 * 
		 * @param openid
		 */
		public ShiroUser(String openid) {
			this.openid = openid;
		}

		/**
		 * 
		 * @param openid
		 */
		public ShiroUser(String openid, String sid) {
			this.openid = openid;
			this.sid = sid;
		}

		public String print() {
			return ToStringBuilder.reflectionToString(this);
		}

		public String getOpenid() {
			return openid;
		}

		public String getSid() {
			return sid;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return openid;
		}

		/**
		 * 重载hashCode,只计算openid;
		 */
		@Override
		public int hashCode() {
			return Objects.hashCode(openid);
		}

		/**
		 * 重载equals,只计算uid;
		 */
		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			ShiroUser other = (ShiroUser) obj;
			if (openid == null) {
				if (other.openid != null) {
					return false;
				}
			} else if (!openid.equals(other.openid)) {
				return false;
			}
			return true;
		}
	}
}
